import matplotlib.pyplot as plt
import numpy as np
import random

def lines(n, w, b, noise):
    x = np.arange(n)
    fun = lambda x: ((w*x) + b)
    y = np.vectorize(fun)(x)
    scatter = lambda x: ((w*x) + b) + random.uniform(-noise, noise)  
    points = np.vectorize(scatter)(x)
    return x, y, points

x, y, points = lines(20, 3, 102, 5)
n1 = 0.00001
initW = 1
initB = 100


w = initW
b = initB
arr = []
wbarr = []
for item in range(10000):
    xStart, yStart, p = lines(20, w, b, 5)
    w1 = 0
    b1 = 0
    sum = 0
    for i, val in enumerate(yStart):
        sum = sum + (((float(val) - float(y[i])) ** 2) / 2)
    for i, val in enumerate(yStart):
        w1 = w1 + (2.0 * (x[i]**2.0) + 2.0 * x[i] - 2.0 * y[i] * x[i])
    for i, val in enumerate(yStart):
        b1 = b1 + (2.0 + 2.0 * x[i] - 2.0 * y[i])
    w1 = (w1 / 20) * n1
    b1 = (b1 / 20) * n1
    w = w - w1
    b = b - b1
    arr.append(sum)
    wbarr.append((w, b))

mi = float('inf')
flat = 0
for i, val in enumerate(arr):
    if mi > val:
        mi = val
        flat = i

print(mi)
print(wbarr[flat])
xf, yf, ps = lines(20, wbarr[flat][0], wbarr[flat][1], 5)

# print(y)
# print(yStart)

xStart, yStart, p = lines(20, initW, initB, 5)

plt.plot(x, points, 'ro')
plt.plot(x, y)
plt.plot(xf, yf)
plt.plot(xStart, yStart)
plt.show()
